Coverage Report

Created: 2024-12-19 06:34

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
D:\a\tools.proto\tools.proto\compiler\src\gen\rust\util.rs
Line
Count
Source
1
// Copyright (c) 2024, BlockProject 3D
2
//
3
// All rights reserved.
4
//
5
// Redistribution and use in source and binary forms, with or without modification,
6
// are permitted provided that the following conditions are met:
7
//
8
//     * Redistributions of source code must retain the above copyright notice,
9
//       this list of conditions and the following disclaimer.
10
//     * Redistributions in binary form must reproduce the above copyright notice,
11
//       this list of conditions and the following disclaimer in the documentation
12
//       and/or other materials provided with the distribution.
13
//     * Neither the name of BlockProject 3D nor the names of its contributors
14
//       may be used to endorse or promote products derived from this software
15
//       without specific prior written permission.
16
//
17
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
21
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29
use crate::compiler::message::{Field, FieldType, Message};
30
use crate::compiler::structure::FixedFieldType;
31
use crate::compiler::util::types::TypeMapper;
32
use crate::gen::base::map::TypePathMapper;
33
use crate::gen::template::Template;
34
use crate::model::protocol::Endianness;
35
use itertools::Itertools;
36
use std::borrow::Cow;
37
38
macro_rules! gen_value_type {
39
    ($prefix: literal, $ty: expr, $suffix: literal) => {
40
        match $ty {
41
            FixedFieldType::Int8 => concat!($prefix, "i8", $suffix),
42
            FixedFieldType::Int16 => concat!($prefix, "i16", $suffix),
43
            FixedFieldType::Int32 => concat!($prefix, "i32", $suffix),
44
            FixedFieldType::Int64 => concat!($prefix, "i64", $suffix),
45
            FixedFieldType::UInt8 => concat!($prefix, "u8", $suffix),
46
            FixedFieldType::UInt16 => concat!($prefix, "u16", $suffix),
47
            FixedFieldType::UInt32 => concat!($prefix, "u32", $suffix),
48
            FixedFieldType::UInt64 => concat!($prefix, "u64", $suffix),
49
            FixedFieldType::Float32 => concat!($prefix, "f32", $suffix),
50
            FixedFieldType::Float64 => concat!($prefix, "f64", $suffix),
51
            FixedFieldType::Bool => concat!($prefix, "bool", $suffix),
52
        }
53
    };
54
}
55
56
pub struct Generic<'a> {
57
    pub name: Cow<'a, str>,
58
    pub default: Option<Cow<'a, str>>,
59
}
60
61
pub struct Generics<T> {
62
    lifetime: bool,
63
    data: T,
64
}
65
66
impl<T> Generics<T> {
67
86
    pub fn new(lifetime: bool, data: T) -> Self {
68
86
        Self {
69
86
            lifetime,
70
86
            data
71
86
        }
72
86
    }
73
}
74
75
86
fn _to_string<'a>(mut generics: impl Iterator<Item=Cow<'a, str>>, lifetime: bool) -> Cow<'a, str>{
76
86
    if let Some(
value12
) = generics.next() {
  Branch (76:12): [True: 4, False: 24]
  Branch (76:12): [True: 8, False: 50]
  Branch (76:12): [Folded - Ignored]
77
12
        let str = generics.join(", ");
78
12
        match (str.is_empty(), lifetime) {
79
0
            (true, false) => format!("<{}>", value).into(),
80
0
            (false, false) => format!("<{}, {}>", value, str).into(),
81
12
            (true, true) => format!("<'a, {}>", value).into(),
82
0
            (false, true) => format!("<'a, {}, {}>", value, str).into(),
83
        }
84
74
    } else if lifetime {
  Branch (84:15): [True: 24, False: 0]
  Branch (84:15): [True: 41, False: 9]
  Branch (84:15): [Folded - Ignored]
85
65
        Cow::Borrowed("<'a>")
86
    } else {
87
9
        Cow::Borrowed("")
88
    }
89
86
}
90
91
impl<'a, T: Iterator<Item = Generic<'a>>> Generics<T> {
92
58
    pub fn to_string(self) -> Cow<'a, str> {
93
58
        let generics = self.data.map(|v| 
match &v.default8
{
94
0
            None => v.name,
95
8
            Some(_) => v.name,
96
58
        
}8
);
97
58
        _to_string(generics, self.lifetime)
98
58
    }
99
100
28
    pub fn to_string_with_defaults(self) -> Cow<'a, str> {
101
28
        let generics = self.data.map(|v| 
match &v.default4
{
102
0
            None => v.name,
103
4
            Some(v1) => format!("{}={}", v.name, v1).into(),
104
28
        
}4
);
105
28
        _to_string(generics, self.lifetime)
106
28
    }
107
}
108
109
pub struct RustUtils;
110
111
impl RustUtils {
112
86
    fn _gen_generics<'a, T: TypeMapper>(msg: &'a Message, type_path_map: &'a TypePathMapper<T>, has_lifetime: bool) -> Generics<impl Iterator<Item = Generic<'a>>> {
113
153
        let unions = msg.fields.iter().filter_map(|v| match &v.ty {
114
12
            FieldType::Union(u) => Some(Generic {
115
12
                name: format!("T{}", v.name).into(),
116
12
                default: Some(format!("{}<'a>", type_path_map.get(&u.r)).into()),
117
12
            }),
118
141
            _ => None,
119
153
        });
120
86
        Generics::new(has_lifetime, unions)
121
86
    }
122
123
28
    pub fn get_generics_for_write<'a, T: TypeMapper>(
124
28
        msg: &'a Message,
125
28
        type_path_map: &'a TypePathMapper<T>,
126
28
    ) -> Generics<impl Iterator<Item = Generic<'a>>> {
127
48
        let has_lifetime = msg.fields.iter().any(|v| {
128
29
            matches!(
129
48
                v.ty,
130
                FieldType::FixedContainer(_)
131
                    | FieldType::Union(_)
132
                    | FieldType::Container(_)
133
                    | FieldType::SizedContainer(_)
134
            )
135
48
        });
136
28
        Self::_gen_generics(msg, type_path_map, has_lifetime)
137
28
    }
138
139
58
    pub fn get_generics<'a, T: TypeMapper>(
140
58
        msg: &'a Message,
141
58
        type_path_map: &'a TypePathMapper<T>,
142
58
    ) -> Generics<impl Iterator<Item = Generic<'a>>> {
143
58
        let has_lifetime = msg.fields.iter().any(|v| {
144
0
            matches!(
145
58
                v.ty,
146
                FieldType::Ref(_)
147
                    | FieldType::Buffer
148
                    | FieldType::SizedBuffer(_)
149
                    | FieldType::FixedContainer(_)
150
                    | FieldType::Union(_)
151
                    | FieldType::Container(_)
152
                    | FieldType::SizedContainer(_)
153
                    | FieldType::Payload
154
            )
155
58
        });
156
58
        Self::_gen_generics(msg, type_path_map, has_lifetime)
157
58
    }
158
}
159
160
impl crate::gen::base::structure::Utilities for RustUtils {
161
1.21k
    fn get_field_type(field_type: FixedFieldType) -> &'static str {
162
1.21k
        
gen_value_type!96
("", field_type, "")
163
1.21k
    }
164
165
198
    fn get_fragment_name(field: &crate::compiler::structure::Field) -> &'static str {
166
198
        //TODO: Check if unwrap is safe
167
198
        let raw_field_type = field.ty.as_fixed().unwrap().bits_type;
168
198
        let raw_field_byte_size = raw_field_type.get_byte_size();
169
198
        match raw_field_byte_size != field.loc.byte_size {
170
12
            true => "unaligned",
171
186
            false => "aligned",
172
        }
173
198
    }
174
175
0
    fn get_fragment_name_mut(field: &crate::compiler::structure::Field) -> &'static str {
176
0
        //TODO: Check if unwrap is safe
177
0
        let raw_field_type = field.ty.as_fixed().unwrap().bits_type;
178
0
        let raw_field_byte_size = raw_field_type.get_byte_size();
179
0
        match raw_field_byte_size != field.loc.byte_size {
180
0
            true => "unaligned",
181
0
            false => "aligned",
182
        }
183
0
    }
184
185
64
    fn get_bit_codec_inline(endianness: Endianness) -> &'static str {
186
64
        match endianness {
187
48
            Endianness::Little => "<bp3d_proto::codec::BitCodecLE as bp3d_proto::codec::BitCodec>",
188
16
            Endianness::Big => "<bp3d_proto::codec::BitCodecBE as bp3d_proto::codec::BitCodec>",
189
        }
190
64
    }
191
192
134
    fn get_byte_codec_inline(endianness: Endianness) -> &'static str {
193
134
        match endianness {
194
134
            Endianness::Little => "<bp3d_proto::codec::ByteCodecLE as bp3d_proto::codec::ByteCodec>",
195
0
            Endianness::Big => "<bp3d_proto::codec::ByteCodecBE as bp3d_proto::codec::ByteCodec>",
196
        }
197
134
    }
198
199
12
    fn get_byte_codec(endianness: Endianness) -> &'static str {
200
12
        match endianness {
201
12
            Endianness::Little => "bp3d_proto::codec::ByteCodecLE",
202
0
            Endianness::Big => "bp3d_proto::codec::ByteCodecBE",
203
        }
204
12
    }
205
}
206
207
impl crate::gen::base::message::Utilities for RustUtils {
208
102
    fn get_value_type(endianness: Endianness, ty: FixedFieldType) -> &'static str {
209
102
        match endianness {
210
102
            Endianness::Little => 
gen_value_type!0
("bp3d_proto::message::util::ValueLE<", ty, ">"),
211
0
            Endianness::Big => gen_value_type!("bp3d_proto::message::util::ValueBE<", ty, ">"),
212
        }
213
102
    }
214
215
10
    fn get_value_type_inline(endianness: Endianness, ty: FixedFieldType) -> &'static str {
216
10
        match endianness {
217
10
            Endianness::Little => 
gen_value_type!0
("bp3d_proto::message::util::ValueLE::<", ty, ">"),
218
0
            Endianness::Big => gen_value_type!("bp3d_proto::message::util::ValueBE::<", ty, ">"),
219
        }
220
10
    }
221
222
9
    fn gen_struct_ref_type(type_name: &str) -> String {
223
9
        format!("{}<&'a [u8]>", type_name)
224
9
    }
225
226
2
    fn gen_message_ref_type(type_name: &str) -> String {
227
2
        format!("{}<'a>", type_name)
228
2
    }
229
}
230
231
121
pub fn gen_where_clause<T: TypeMapper>(
232
121
    template: &Template,
233
121
    field: &Field,
234
121
    type_path_map: &TypePathMapper<T>,
235
121
    function: &str,
236
121
) -> String {
237
121
    match &field.ty {
238
13
        FieldType::Union(v) => template
239
13
            .scope()
240
13
            .var("name", &field.name)
241
13
            .var("type_name", type_path_map.get(&v.r))
242
13
            .var("discriminant_type", type_path_map.get(&v.r.discriminant.root))
243
13
            .render(function, &["where"])
244
13
            .unwrap(),
245
108
        _ => "".into(),
246
    }
247
121
}